/* basicObject is main displayObject3D */
/* this class uses keyboard event. +,-,up,down, left, right */
package net.sangpil.applications.viewer
{
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	import gs.TweenLite;
	import gs.easing.Cubic;
	
	import net.sangpil.applications.viewer.event.Viewer3dEvent;
	
	import org.papervision3d.objects.DisplayObject3D;
	import org.papervision3d.view.BasicView;

	[Event(name = "camera_pos_change", type = "net.sangpil.applications.viewer.event.CameraPositionViewerEvent")]
	[Event(name = "object_pos_change", type = "net.sangpil.applications.viewer.event.CameraPositionViewerEvent")]
	public class Viewer3D extends BasicView
	{
		private var guiClip:Navi_3DControllerClip;
		private var vw:Number;
		private var vh:Number;
		private var viewerCover:btn_invisible;
		private var mPoint:Point = new Point();
		private var posObject:Object = {x:0,y:0,z:0, rotationX:0,rotationY:0,rotationZ:0, ease:Cubic.easeOut, onComplete:onFinishTween};
		private var posCamera:Object = {x:0,y:0,z:0, zoom:0, ease:Cubic.easeOut};
		private var lookupTF:Boolean = true;
		
		public var basicObject:DisplayObject3D;
		
		public function Viewer3D(viewportWidth:Number=640, viewportHeight:Number=480, scaleToStage:Boolean=false, interactive:Boolean=false, cameraType:String="Free")
		{
			super(viewportWidth, viewportHeight-48.05, scaleToStage, interactive, cameraType);
			this.vw = viewportWidth;
			this.vh = viewportHeight-48.05;
			
			this.addEventListener(Event.ADDED_TO_STAGE, onStage);
		}
		
		private function onStage(e:Event):void
		{
			this.add3DObjController();
			
			/* add 3d object controller */
			this.setLayout();
			this.setEvent();
			this.easingSet();
		}
		
		private function add3DObjController():void
		{
			/* set my basic 3D object. */			
			this.basicObject = new DisplayObject3D();
			this.scene.addChild(this.basicObject);
			
			this.camera.lookAt(this.basicObject);
			this.camera.y = 0;
			this.camera.z = -2000;
			this.camera.fov = 70;
		}
		
		private function setLayout():void
		{
			this.graphics.beginFill(0x333333);
			this.graphics.drawRect(0,0,this.vw, this.vh);
			this.graphics.endFill();
			
			this.guiClip = new Navi_3DControllerClip();
			this.addChild(this.guiClip);
			
			this.guiClip.y = this.vh+2;
			this.guiClip.changableBg.width = this.vw - this.guiClip.changableBg.x;
			
			
			
			this.viewerCover = new btn_invisible();
			this.addChild(this.viewerCover);
			
			this.viewerCover.width = this.vw;
			this.viewerCover.height = this.vh;
			this.viewerCover.x = 0;
			this.viewerCover.y = 0;
		}
		
		private function easingSet():void
		{
			this.posCamera.x = this.camera.x;
			this.posCamera.y = this.camera.y;
			this.posCamera.z = this.camera.z;
			
			this.posObject.x = this.basicObject.x;
			this.posObject.y = this.basicObject.y;
			this.posObject.z = this.basicObject.z;
			this.posObject.rotationX = this.basicObject.rotationX;
			this.posObject.rotationY = this.basicObject.rotationY;
			this.posObject.rotationZ = this.basicObject.rotationZ;
		}
		
		private function setEvent():void
		{
			this.guiClip.goBack.buttonMode = true;
			this.guiClip.goBack.addEventListener(MouseEvent.MOUSE_DOWN, mDown);
			this.guiClip.magicZoom.addEventListener(MouseEvent.MOUSE_DOWN, mDown);
			this.guiClip.maginPad.addEventListener(MouseEvent.MOUSE_DOWN, mDown);
			this.guiClip.lookUpBtn.addEventListener(MouseEvent.MOUSE_DOWN, mDown);
			this.viewerCover.addEventListener(MouseEvent.MOUSE_DOWN, mDown);
			this.viewerCover.addEventListener(MouseEvent.MOUSE_WHEEL, onWheel);
			this.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
		}
		
		private function onWheel(e:MouseEvent):void
		{
			//var dis:Number = Number3D.sub(this.camera.position, this.basicObject.position).moduloSquared;
			this.camera.moveForward(10*e.delta);
			this.camera.lookAt(this.basicObject);
			this.updateControllerInfo();
			this.onRenderTick();
			//trace(this.camera.x , this.camera.z);
		}
		
		
		private function mDown(e:MouseEvent):void
		{
			switch(e.currentTarget.name)
			{	
				case this.guiClip.goBack.name:
					//TweenLite.to(this.camera, 1, this.posCamera);
					//TweenLite.to(this.basicObject, 1, this.posObject);
					this.test_Tween();
				break;
				case this.guiClip.lookUpBtn.name:
					if(this.lookupTF)
					{
						this.guiClip.lookUpBtn.onOffTxt.text = "off";
						this.lookupTF = false;
						//this.camera.lookAt(
					}else{
						this.guiClip.lookUpBtn.onOffTxt.text = "on";
						this.lookupTF = true;
					}
				break;
				default:
					var nb:DisplayObjectContainer = e.currentTarget as DisplayObjectContainer;
					this.mPoint.x = nb.mouseX;
					this.mPoint.y = nb.mouseY;
					nb.addEventListener(MouseEvent.MOUSE_MOVE, mMove);
					nb.addEventListener(MouseEvent.MOUSE_UP, mUp);
					nb.addEventListener(MouseEvent.MOUSE_OUT, mOut);
			}
		}
		
		public function test_Tween():void
		{
			TweenLite.to(this.basicObject, 1, {z:this.basicObject.x + 100, y:this.basicObject.y + 100});
		}
		
		private function mUp(e:MouseEvent):void
		{
			var nb:DisplayObjectContainer = e.currentTarget as DisplayObjectContainer;
			nb.removeEventListener(MouseEvent.MOUSE_MOVE, mMove);
			nb.removeEventListener(MouseEvent.MOUSE_UP, mUp);
			nb.removeEventListener(MouseEvent.MOUSE_OUT, mOut);
		}
		private var radian:Number = Math.PI/2+Math.PI;
		private function mMove(e:MouseEvent):void
		{
			var nb:DisplayObjectContainer = e.currentTarget as DisplayObjectContainer;
			//trace(nb.mouseX, nb.mouseY, nb.name); 
			
			var disX:Number = this.mPoint.x - nb.mouseX; 
			var disY:Number = this.mPoint.y - nb.mouseY;
			switch(nb.name)
			{
				case this.viewerCover.name:
					this.camera.y += disY*-160;
					if(this.lookupTF)
					{
						var dis:Number = Math.sqrt(this.camera.x*this.camera.x + this.camera.z*this.camera.z);
						//this.radian = Math.atan2(this.camera.x, this.camera.z);
						
						//trace(radian);
						radian += disX/10;
						
						this.camera.x = Math.cos(radian)*dis;
						this.camera.z = Math.sin(radian)*dis;		
										
						
						//this.basicObject.rotationY += disX*8;
						this.camera.lookAt(this.basicObject);
					}else{
						this.camera.x += disX*60;
					}
					
				break;
				case "maginPad":
					this.basicObject.rotationX += disY*2;
					this.basicObject.rotationY += disX*2;
				break;
				case "magicZoom":
					this.camera.fov += disY*1/2;
				break;
			}
			this.mPoint.x = nb.mouseX;
			this.mPoint.y = nb.mouseY;
			this.updateControllerInfo();
			this.onRenderTick();
		}
		
		private function mOut(e:MouseEvent):void
		{
			var nb:DisplayObjectContainer = e.currentTarget as DisplayObjectContainer;
			nb.removeEventListener(MouseEvent.MOUSE_MOVE, mMove);
			nb.removeEventListener(MouseEvent.MOUSE_UP, mUp);
			nb.removeEventListener(MouseEvent.MOUSE_OUT, mOut);	
		}
		
		private function updateControllerInfo():void
		{
			/* update infomation */
			this.guiClip.tf_X.text = Math.round(this.basicObject.x).toString();
			this.guiClip.tf_Y.text = Math.round(this.basicObject.y).toString();
			this.guiClip.tf_Z.text = Math.round(this.basicObject.z).toString();
			this.guiClip.tf_rotationX.text = Math.round(this.basicObject.rotationX).toString();
			this.guiClip.tf_rotationY.text = Math.round(this.basicObject.rotationY).toString();
			this.guiClip.tf_rotationZ.text = Math.round(this.basicObject.rotationZ).toString();
			
			this.guiClip.c_tf_zoom.text = Math.round(this.camera.zoom).toString();
			this.guiClip.c_tf_fov.text = Math.round(this.camera.fov).toString();
			this.guiClip.c_tf_X.text = Math.round(this.camera.x).toString();
			this.guiClip.c_tf_Y.text = Math.round(this.camera.y).toString();
			this.guiClip.c_tf_Z.text = Math.round(this.camera.z).toString();
			this.guiClip.c_tf_rotationX.text = Math.round(this.camera.rotationX).toString();
			this.guiClip.c_tf_rotationY.text = Math.round(this.camera.rotationY).toString();
			this.guiClip.c_tf_rotationZ.text = Math.round(this.camera.rotationZ).toString();
			
			this.dispatchEvent(new Viewer3dEvent(this.camera.x, this.camera.y, this.camera.z, this.camera.rotationX, this.camera.rotationY, this.camera.rotationZ, Viewer3dEvent.CAMERA_POS_CHANGE));
			this.dispatchEvent(new Viewer3dEvent(this.basicObject.x, this.basicObject.y, this.basicObject.z, this.basicObject.rotationX, this.basicObject.rotationY, this.basicObject.rotationZ, Viewer3dEvent.OBJECT_POS_CHANGE));
			
		}
		
		private function onKeyDown(e:KeyboardEvent):void
		{
			//trace(e.keyCode);
			switch(e.keyCode)
			{
				case 38: //up
					//this.cube.rotationX += 5;
					this.camera.y += 10;
				break;
				case 40: //down
					//this.cube.rotationX -= 5;
					this.camera.y -= 10;
				break;
				case 37: //left
					this.basicObject.rotationY += 5;
				break;
				case 39: //right
					this.basicObject.rotationY -= 5;
				break;
				case 187: //=,+
					this.camera.zoom += 5;
				break;
				case 189: //-
					this.camera.zoom -= 5;
				break;
			}
			this.singleRender();
			this.updateControllerInfo();
		}
		
		private function onFinishTween():void
		{
			trace("got");
			this.updateControllerInfo();
		}
		
		public function updateCamera(position:Point):void
		{
			this.camera.x = position.x;
			this.camera.z = position.y;
			this.camera.lookAt(this.basicObject);
			this.updateControllerInfo();
			onRenderTick();
		}
		
		public override function singleRender():void
		{
			onRenderTick();
		}
	}
}